package com.cnap.multiclouldmgmt.vm.task;

import com.cnap.multiclouldmgmt.controller.K8sClusterController;
import com.cnap.multiclouldmgmt.model.k8sModels.K8sClusterBasicModel;
import com.cnap.multiclouldmgmt.model.k8sModels.NodeModel;
import com.cnap.multiclouldmgmt.model.scale.db.ScalingGroupPO;
import com.cnap.multiclouldmgmt.model.scale.db.ScalingResourcePO;
import com.cnap.multiclouldmgmt.model.vmScale.ScaleGroupPolicy;
import com.cnap.multiclouldmgmt.model.vmScale.VmInfo;
import com.cnap.multiclouldmgmt.repository.master.*;
import com.cnap.multiclouldmgmt.service.K8sClusterService;
import com.cnap.multiclouldmgmt.service.MultiCloudMgmtService;
import com.cnap.multiclouldmgmt.service.VmResourceService;
import com.cnap.multiclouldmgmt.util.CnapCloudMgmtConstants;
import com.cnap.multiclouldmgmt.util.DateUtils;
import com.cnap.multiclouldmgmt.vm.service.VMScale;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

@Service
public class AsyncInvokeService {

    private final static Logger LOGGER = LoggerFactory.getLogger(K8sClusterController.class);
    @Autowired
    private VMScaleMapper vmScaleMapper;

    @Autowired
    private K8sClusterService k8sClusterService;

    @Autowired
    private MultiCloudMgmtService multiCloudMgmtService;

    @Autowired
    private VmResourceService vmResourceService;

    @Autowired
    private ScalingGroupMapper scalingGroupMapper;

    @Autowired
    private VMInfoMapper vmInfoMapper;

    @Autowired
    private ScalingResourceMapper scalingResourceMapper;

    @Autowired
    private CnapKeyValueMapper cnapKeyValueMapper;


    /**
     *
     * @param policy
     */
    @Async("scaleTaskExecutor")
    public void exec(ScaleGroupPolicy policy) {
        while(true){
            try {
            Thread thread = Thread.currentThread();
            VMScale.currentThreadAndScalePolicyMap.put(policy.getId(),thread);

                /**
                 * 为了snoar扫描
                 * 增加一个跳出的机制
                 * 防止死循环
                 */
            if (StringUtils.equals(cnapKeyValueMapper.getKvByKey(CnapCloudMgmtConstants.BREAK_ASYNC),CnapCloudMgmtConstants.BREAK_ASYNC)){
                break;
            }
            
            //查询该伸缩组的cpu利用率
            Double useRate = cacluateResource(policy);
            LOGGER.info("云商：{}，集群{}，资源是{}，使用率是{}",policy.getProvider(),policy.getClusterName(),policy.getResource(),useRate);
            boolean isColdTime = isCoolTime(policy.getUpdateTime(),policy.getCoolTime());
            //查找是否在冷却时间内

            if(useRate != null && StringUtils.equalsIgnoreCase("max",policy.getType()) && useRate.compareTo(Double.valueOf(policy.getValue())/100)>0){
                Integer policeTime = VMScale.scalGroupOverThresholdTime.getOrDefault(policy.getId(), 0);
                VMScale.scalGroupOverThresholdTime.put(policy.getId(),policeTime+1);
                LOGGER.info("扩容策略：是否处于冷却期：{}，伸缩组{}满足扩容条件{}次",isColdTime,policy.getGroupName(),VMScale.scalGroupOverThresholdTime.get(policy.getId()));
                if(!isColdTime && VMScale.scalGroupOverThresholdTime.get(policy.getId())>=policy.getContinuousNum()){
                    try {
//                        List<String> list = Arrays.asList(policy.getCloudResourceIds().split(","));
//                        vmResourceService.addNewResource(policy.getProvider(),policy.getClusterName(),policy.getNum(),policy.getSystemImage(),
//                                4,50,policy.getLabel());
//                        ScalingGroupPO scalingGroupPO = scalingGroupMapper.selectGroupById(policy.getGroupId());
//                        if(scalingGroupPO != null && scalingGroupPO.getExpectNum() >= scalingGroupPO.getMaxNum()){
//                            LOGGER.info("{}已达到最大数量节点，不支持再扩容",policy.getGroupName());
//                        } else  if(scalingGroupPO != null && scalingGroupPO.getExpectNum() < scalingGroupPO.getMaxNum()){

//                        int num =scalingGroupPO.getMaxNum()-scalingGroupPO.getExpectNum()>=policy.getNum()?policy.getNum()
//                                :scalingGroupPO.getMaxNum()-scalingGroupPO.getExpectNum();

                       // List<VmInfo> vmInfos = selectScaleOptimalNode(policy.getNum(), policy.getUserName(), policy.getResource(), list);

                        ScalingResourcePO resourcePO = scalingResourceMapper.selectResourceById(policy.getCloudResourceIds());

                        //调用扩容接口

                        int flag =vmResourceService.addNewResourceForScale(policy.getProvider(),policy.getClusterName(),resourcePO.getCpuCores(),resourcePO.getMemory(),policy.getLabel());
                        LOGGER.info("调用扩容接口，clustername 是 {},扩容数量是{},时间是{}",policy.getClusterName(),flag,DateUtils.changeDateFormatYYYYMMDDHHMMSS(new Date()));
                        if(flag<0){
                            LOGGER.info("调用扩容接口失败，clustername是{}"+policy.getClusterName());
                        }else{
                            Date date = new Date();
                            vmScaleMapper.updateVmScalePolicyTime(policy.getId(),DateUtils.changeDateFormatYYYYMMDDHHMMSS(date));
                            //更新超过阈值次数为0
                            VMScale.scalGroupOverThresholdTime.put(policy.getId(),0);
                            scalingGroupMapper.updateExpectNum(policy.getType(),flag,policy.getGroupId());
                            //更新冷却时间
                            policy.setUpdateTime(date);
                        }
//                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }else if(useRate != null &&StringUtils.equalsIgnoreCase("min",policy.getType()) && useRate.compareTo(Double.valueOf(policy.getValue())/100)<0){
                Integer policeTime = VMScale.scalGroupOverThresholdTime.getOrDefault(policy.getId(), 0);
                VMScale.scalGroupOverThresholdTime.put(policy.getId(),policeTime+1);
                LOGGER.info("缩容策略：是否处于冷却期：{}，伸缩组{}：policeId:{}满足缩容条件{}次",isColdTime,policy.getGroupName(),policy.getId(),VMScale.scalGroupOverThresholdTime.get(policy.getId()));
                if(!isColdTime && VMScale.scalGroupOverThresholdTime.get(policy.getId())>=policy.getContinuousNum()){
                    ScalingGroupPO scalingGroupPO = scalingGroupMapper.selectGroupById(policy.getGroupId());
                    //满足缩容条件
                    if(scalingGroupPO != null && scalingGroupPO.getExpectNum() > scalingGroupPO.getMinNum()){
                        //调用缩容接口
                        int num =scalingGroupPO.getExpectNum()-scalingGroupPO.getMinNum()>=policy.getNum()?policy.getNum()
                                :scalingGroupPO.getExpectNum()-scalingGroupPO.getMinNum();
                        LOGGER.info("调用缩容接口，clustername 是 {},缩容数量是{},时间是{}",policy.getClusterName(),num,DateUtils.changeDateFormatYYYYMMDDHHMMSS(new Date()));
                        boolean flag =vmResourceService.delResource(policy.getProvider(),policy.getClusterName(),policy.getLabel(),
                                policy.getDeletePolicy(),num);
                        if(!flag){
                            LOGGER.info("缩容失败，clustername是 {}"+policy.getClusterName());
                        }
                        //更新冷却时间
                        Date date = new Date();
                        vmScaleMapper.updateVmScalePolicyTime(policy.getId(),DateUtils.changeDateFormatYYYYMMDDHHMMSS(date));
                        //更新超过阈值次数为0
                        VMScale.scalGroupOverThresholdTime.put(policy.getId(),0);
                        scalingGroupMapper.updateExpectNum(policy.getType(),num,policy.getGroupId());
                        policy.setUpdateTime(date);
                    }else if(scalingGroupPO != null && scalingGroupPO.getExpectNum() <= scalingGroupPO.getMinNum()){
                        LOGGER.info("{}已达到最少数量节点，不支持再缩容",policy.getGroupName());
                    }

                }
            }else{
                VMScale.scalGroupOverThresholdTime.put(policy.getId(),0);
                LOGGER.info("伸缩组策略：{}：{}:{} 资源使用率未达到阈值，无需扩缩容，将阈值置0",policy.getGroupName(),policy.getId(),policy.getType());
            }
            Integer policeTime = VMScale.scalGroupOverThresholdTime.getOrDefault(policy.getId(), 0);
            LOGGER.debug("[monitor]: monitorscale policy group name: {},cluser name:{},type {},provide :{},time :{}",
                    policy.getGroupName(), policy.getClusterName(),policy.getType(), policy.getProvider(), DateUtils.changeDateFormatYYYYMMDDHHMMSS(new Date()));

                Thread.sleep(policy.getDuration()*60* 1000L);
            } catch (InterruptedException e) {
                //防止线程异常，暂停失败
                LOGGER.error("监控策略组{}策略{}线程被终止",policy.getGroupName(),policy.getId());
                Thread.currentThread().interrupt();
                break;
            }
        }

    }

    /**
     *
     * @param num
     * @param user
     * @param resource
     * @param candidateNodeList
     * @return
     */
    private List<VmInfo> selectScaleOptimalNode(int num,String user,String resource,List<String> candidateNodeList){
        List<VmInfo> vmInfo = vmInfoMapper.getVmInfo(candidateNodeList, user, resource, num);
        return vmInfo;

    }



    /**
     *
     * @param base
     * @param expireTime
     * @return
     */
    private boolean isCoolTime(Date base,int expireTime){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(base);
        calendar.add(Calendar.SECOND, expireTime);
        Date time = calendar.getTime();
        if(time.before(new Date())){
            return false;
        }
        return true;
    }

    /**
     *
     * @param policy
     * @return
     */
    private Double cacluateResource(ScaleGroupPolicy policy) {
        K8sClusterBasicModel k8sClusterInfoByName = multiCloudMgmtService.getK8sClusterInfoByName(policy.getClusterName());
        if(k8sClusterInfoByName == null){
            return null;
        }
        List<NodeModel> nodeInfos =null;
        try {
            nodeInfos = k8sClusterService.getAllNodeInfo(k8sClusterInfoByName, "",
                    CnapCloudMgmtConstants.NODE_APP_LABEL_ID, policy.getLabel());
        } catch (Exception e) {
            LOGGER.error("get nodeInfo failed,cluster name is {},label is {}",policy.getClusterName(),policy.getLabel());
            e.printStackTrace();
        }
        if(nodeInfos == null || nodeInfos.size()==0){
            return null;
        }
        double total = 0;
        double used = 0;
        for(NodeModel nodeModel:nodeInfos){
            if(StringUtils.equalsIgnoreCase(policy.getResource(),"cpu")){
                total += nodeModel.getNodeCpuQuotaByN();
                used+=nodeModel.getNodeCpuUseByN();
            }else if(StringUtils.equalsIgnoreCase(policy.getResource(),"memory")){
                total+=nodeModel.getNodeMemQuotaByKi();
                used+=nodeModel.getNodeMemUseNumByKi();

            }
        }
        if(total == 0){
            return 0d;
        }
        double result =used/total;
        return  result;
    }

}
